// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module i2c_slave_main_wrapper
(
// ------------------------
// Clock and Reset signals
// ------------------------
   input       clk, 													//clock for sequential logic 
   input       rst_n, 												//reset signal from PLL Lock, resets state machine to initial state
// ----------------------------
// inputs and outputs
// ---------------------------- 
   //IIC interface
   input           i2c_data_in,
   input           i2c_clk_in,
   output          i2c_data_oe,
   output          i2c_clk_oe,
   
   //AVMM interface	
	input           waitrequest,
	input           readdatavalid,
	input  [31:0]   readdata,
	
	output [31:0]   address,
	output          write,
	output [31:0]   writedata,
	output reg      read,
	output [3:0]    byteenable

);


//////////////////////////////////////////////////////////////////////////////////
// States for FSM
//////////////////////////////////////////////////////////////////////////////////
	localparam ST_INIT               = 4'd0;
	localparam ST_WAITREQUEST        = 4'd1;
	localparam ST_RD_D0              = 4'd2;
	localparam ST_RD_D1_WAIT         = 4'd3;
	localparam ST_RD_D1              = 4'd4;
	localparam ST_RD_D2_WAIT         = 4'd5;
	localparam ST_RD_D2              = 4'd6;
	localparam ST_RD_D3_WAIT         = 4'd7;
	localparam ST_RD_D3              = 4'd8;


//////////////////////////////////////////////////////////////////////////////////
// Parameters
//////////////////////////////////////////////////////////////////////////////////
	localparam  LOW =1'b0;
	localparam  HIGH=1'b1;

//////////////////////////////////////////////////////////////////////////////////
// Internal Signals
//////////////////////////////////////////////////////////////////////////////////
	reg  [3:0]	rstate;
	
	//AVMM interface from IIC slave to AVMM master IP, need to be controlled by internal logic
	wire        ip_read;
   reg  [31:0] ip_readdata;
   reg         ip_readdatavalid;
   reg	      ip_waitrequest;
	
	reg  [31:0] readdata_store;
	
	reg  [31:0] address_store;
	
//////////////////////////////////////////////////////////////////////////////////
// Sequencial Logic for read 
//////////////////////////////////////////////////////////////////////////////////	

   always @ (posedge clk or negedge rst_n) begin
	   if(!rst_n) begin
		   read                    <= LOW;
		   ip_readdata             <= 32'h0;
			ip_readdatavalid        <= LOW;
			ip_waitrequest          <= LOW;
			readdata_store          <= 32'h0;
			address_store           <= 32'h0;
			
			rstate                  <= ST_INIT;
		end
		
		else begin
		   case(rstate)
			   ST_INIT: begin
				   read              <= ip_read;
		         ip_readdata       <= readdata;
			      ip_readdatavalid  <= readdatavalid;
			      ip_waitrequest    <= waitrequest;
					readdata_store    <= 32'h0;
					address_store     <= address;
					
					if(ip_read) begin
					   rstate         <= ST_WAITREQUEST;           //The first read request from IIC master
					end
				end
				
				ST_WAITREQUEST: begin
				   read              <= ip_read;
					ip_readdata       <= readdata;
			      ip_readdatavalid  <= readdatavalid;
			      ip_waitrequest    <= waitrequest;
					
					if(readdatavalid) begin
					   readdata_store <= readdata;
						address_store  <= address;
					   rstate         <= ST_RD_D0;
					end
					else begin
					   rstate         <= ST_WAITREQUEST;
					end
					
				end
				
				ST_RD_D0: begin
				   read              <= ip_read;
		         ip_readdata       <= readdata;
			      ip_readdatavalid  <= readdatavalid;
					
               rstate            <= ST_RD_D1_WAIT;
				end
				
				ST_RD_D1_WAIT: begin
		         ip_readdata       <= 32'h0;
			      ip_readdatavalid  <= LOW;
			      ip_waitrequest    <= LOW;
					
					if(ip_read && (address == address_store)) begin
				      read           <= LOW;	
					   rstate         <= ST_RD_D1;
					end
					else if (ip_read && (address != address_store)) begin
					   read           <= ip_read;
					   rstate         <= ST_WAITREQUEST;
					end
				end
				
				ST_RD_D1: begin
				   read              <= LOW;
		         ip_readdata       <= readdata_store;
			      ip_readdatavalid  <= HIGH;
			      ip_waitrequest    <= LOW;
					address_store     <= address;
					
               rstate            <= ST_RD_D2_WAIT;
				end
				
				ST_RD_D2_WAIT: begin
		         ip_readdata       <= 32'h0;
			      ip_readdatavalid  <= LOW;
			      ip_waitrequest    <= LOW;
					
					if(ip_read && (address == address_store)) begin
				      read           <= LOW;	
					   rstate         <= ST_RD_D2;
					end
					else if (ip_read && (address != address_store)) begin
					   read           <= ip_read;
						rstate         <= ST_WAITREQUEST;
					end
				end
				
				ST_RD_D2: begin
				   read              <= LOW;
		         ip_readdata       <= readdata_store;
			      ip_readdatavalid  <= HIGH;
			      ip_waitrequest    <= LOW;
					address_store     <= address;
					
               rstate            <= ST_RD_D3_WAIT;
				end
				
				ST_RD_D3_WAIT: begin
		         ip_readdata       <= 32'h0;
			      ip_readdatavalid  <= LOW;
			      ip_waitrequest    <= LOW;
					
					if(ip_read && (address == address_store)) begin 
					   read           <= LOW;
						rstate         <= ST_RD_D3;
					end
					else if (ip_read && (address != address_store)) begin
					   read           <= ip_read;
						rstate         <= ST_WAITREQUEST;
					end
				end
				
				ST_RD_D3: begin
				   read              <= LOW;
		         ip_readdata       <= readdata_store;
			      ip_readdatavalid  <= HIGH;
			      ip_waitrequest    <= LOW;
					address_store     <= address;
					
               rstate            <= ST_INIT;
				end
				
				default: begin
				   rstate            <= ST_INIT;
				end
				
			endcase
		end
	end
	
//////////////////////////////////////////////////////////////////////////////////
// Instance
//////////////////////////////////////////////////////////////////////////////////
	main_i2c_slave main_i2c_slave (
    .clk           ( clk                        ), //should use clock from LVDS_TX internal PLL
    .rst_n         ( rst_n                      ), 
    .i2c_data_in   ( i2c_data_in                ), 
    .i2c_clk_in    ( i2c_clk_in                 ), 
    .i2c_data_oe   ( i2c_data_oe                ), 
    .i2c_clk_oe    ( i2c_clk_oe                 ),    
    .address       ( address                    ), //AVMM master      
    .read          ( ip_read                    ),         
    .readdata      ( ip_readdata                ),     
    .readdatavalid ( ip_readdatavalid           ),
    .waitrequest   ( ip_waitrequest             ), 
    .write         ( write                      ),       
    .byteenable    ( byteenable                 ), 
    .writedata     ( writedata                  )
);
	
endmodule
	